<!--
 * @Description: 文本框节点组件
 * @Author: Auto
 * @Date: 2025-01-27
-->
<template>
  <div 
    class="text-node" 
    :class="nodeClass"
    :style="nodeStyle"
    @mousedown="handleNodeMouseDown"
    @dblclick="handleNodeDoubleClick"
  >
    <Handle id="top" type="target" position="top" />
    <Handle id="bottom" type="source" position="bottom" />
    <Handle id="left" type="target" position="left" />
    <Handle id="right" type="source" position="right" />
    
    <!-- 删除按钮 -->
    <div class="delete-btn" @click.stop="handleDelete" title="删除节点">
      <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path d="M11 3.5L3 11.5M3 3.5L11 11.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
      </svg>
    </div>
    
    <!-- 调整大小拖拽点 -->
    <div 
      class="resize-handle" 
      @mousedown.stop="handleResizeStart"
      title="拖拽调整大小"
    ></div>
    
    <!-- 进度条模式 -->
    <div v-if="progress < 100" class="progress-container">
      <div class="progress-bar-wrapper">
        <div class="progress-bar" :style="{ width: `${progress}%` }"></div>
      </div>
      <div class="progress-text">{{ Math.round(progress) }}%</div>
    </div>
    
    <!-- 节点内容模式 -->
    <template v-else>
      <div class="text-content">
        <input
          v-if="isEditingTitle"
          v-model="editingTitle"
          class="text-title-input"
          @blur="handleTitleBlur"
          @keydown.enter="handleTitleBlur"
          @keydown.esc="cancelTitleEdit"
          @click.stop="handleInputClick"
          @mousedown.stop="handleInputMouseDown"
          ref="titleInputRef"
        />
        <div
          v-else
          class="text-title"
          @click.stop="startEditTitle"
          :title="title || '单击编辑标题'"
        >
          {{ title || '单击编辑标题' }}
        </div>
        <textarea
          v-if="isEditingText"
          v-model="editingText"
          class="text-body-input"
          @blur="handleTextBlur"
          @keydown.esc="cancelTextEdit"
          @click.stop="handleTextareaClick"
          @mousedown.stop="handleTextareaMouseDown"
          ref="textInputRef"
        />
        <div
          v-else
          class="text-body"
          @click.stop="startEditText"
          :title="text || '单击编辑内容'"
          v-html="renderTextWithIdCard(text || '单击编辑内容')"
          ref="textBodyRef"
        ></div>
      </div>
    </template>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, onUnmounted, onMounted, watch, nextTick } from 'vue'
import { Handle } from '@vue-flow/core'

Handle.name = 'Handle'

interface Props {
  title?: string // 标题
  text?: string // 文本内容
  progress?: number // 进度 0-100
  nodeId?: string
  width?: number
  height?: number
  selected?: boolean // 是否选中
}

const props = withDefaults(defineProps<Props>(), {
  title: '',
  text: '',
  progress: 100,
  nodeId: '',
  width: undefined,
  height: undefined,
  selected: false
})

const emit = defineEmits<{
  delete: [nodeId: string]
  resize: [nodeId: string, width: number, height: number]
  update: [nodeId: string, data: { title?: string; text?: string }]
  createPersonNode: [idNumber: string]
}>()

// 编辑状态
const isEditingTitle = ref(false)
const isEditingText = ref(false)
const editingTitle = ref('')
const editingText = ref('')
const titleInputRef = ref<HTMLInputElement | null>(null)
const textInputRef = ref<HTMLTextAreaElement | null>(null)
const textBodyRef = ref<HTMLDivElement | null>(null)

// 开始编辑标题
const startEditTitle = () => {
  editingTitle.value = props.title || ''
  isEditingTitle.value = true
  // 使用nextTick和requestAnimationFrame确保DOM完全更新并渲染
  nextTick(() => {
    requestAnimationFrame(() => {
      if (titleInputRef.value) {
        // 先focus，确保输入框获得焦点并显示光标
        titleInputRef.value.focus()
        // 使用setTimeout确保浏览器已经处理了focus事件并显示光标
        setTimeout(() => {
          if (titleInputRef.value && document.activeElement === titleInputRef.value) {
            // 将光标定位到文本末尾（双击进入编辑时）
            const length = titleInputRef.value.value.length
            if (length > 0) {
              titleInputRef.value.setSelectionRange(length, length)
            }
          }
        }, 10)
      }
    })
  })
}

// 完成编辑标题
const handleTitleBlur = () => {
  isEditingTitle.value = false
  if (editingTitle.value !== props.title) {
    emit('update', props.nodeId, { title: editingTitle.value })
  }
}

// 取消编辑标题
const cancelTitleEdit = () => {
  editingTitle.value = props.title || ''
  isEditingTitle.value = false
}

// 开始编辑文本
const startEditText = () => {
  editingText.value = props.text || ''
  isEditingText.value = true
  // 使用nextTick和requestAnimationFrame确保DOM完全更新并渲染
  nextTick(() => {
    requestAnimationFrame(() => {
      if (textInputRef.value) {
        // 先focus，确保文本域获得焦点并显示光标
        textInputRef.value.focus()
        // 使用setTimeout确保浏览器已经处理了focus事件并显示光标
        setTimeout(() => {
          if (textInputRef.value && document.activeElement === textInputRef.value) {
            // 将光标定位到文本末尾（双击进入编辑时）
            const length = textInputRef.value.value.length
            if (length > 0) {
              textInputRef.value.setSelectionRange(length, length)
            }
          }
        }, 10)
      }
    })
  })
}

// 完成编辑文本
const handleTextBlur = () => {
  isEditingText.value = false
  if (editingText.value !== props.text) {
    emit('update', props.nodeId, { text: editingText.value })
  }
}

// 取消编辑文本
const cancelTextEdit = () => {
  editingText.value = props.text || ''
  isEditingText.value = false
}

// 处理输入框点击事件 - 确保光标显示
const handleInputClick = (e: MouseEvent) => {
  const target = e.target as HTMLInputElement
  if (target && document.activeElement !== target) {
    // 如果输入框还没有焦点，确保获得焦点
    target.focus()
  }
  // 让浏览器正常处理光标定位，不强制设置光标位置
}

// 处理输入框鼠标按下事件
const handleInputMouseDown = (e: MouseEvent) => {
  // 不阻止默认行为，让浏览器正常处理光标定位
  e.stopPropagation()
}

// 处理文本域点击事件 - 确保光标显示
const handleTextareaClick = (e: MouseEvent) => {
  const target = e.target as HTMLTextAreaElement
  if (target && document.activeElement !== target) {
    // 如果文本域还没有焦点，确保获得焦点
    target.focus()
  }
  // 让浏览器正常处理光标定位
}

// 处理文本域鼠标按下事件
const handleTextareaMouseDown = (e: MouseEvent) => {
  // 不阻止默认行为，让浏览器正常处理光标定位
  e.stopPropagation()
}

// 身份证号码正则表达式（18位或15位）
// 18位：前17位数字 + 最后一位数字或X/x
// 15位：15位数字
// 注意：先匹配18位，再匹配15位，避免18位被15位模式截断
const idCardRegex = /(\d{17}[\dXx]|\d{15})/g

// SVG图标HTML
const handIconSvg = `<svg t="1763026344096" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1615" width="14" height="14" style="display: inline-block; vertical-align: middle; margin-right: 4px;"><path d="M864.65 336.975v-0.079c56.91 0 98.58 45.804 98.58 102.321v204.485c0 193.26-26.94 349.932-317.283 349.932-127.055 0-187.156-25.363-239.616-68.135a103.778 103.778 0 0 1-19.377-14.966L99.249 624.64c-48.994-49.034-26.584-117.957 7.759-152.222 34.265-34.343 105.433-39.975 145.723 0l62.425 62.307V137.689a102.676 102.676 0 0 1 103.03-102.243c56.91 0 99.643 45.726 99.643 102.243v103.817a102.4 102.4 0 0 1 48.6-12.209c45.293 0 80.463 29.066 94.287 69.317 15.754-9.728 34.856-15.517 54.863-15.517 45.292 0 80.384 29.065 94.208 69.395a95.31 95.31 0 0 1 52.145-15.517h2.757z m44.19 306.727v0.158h0.236V445.755c0-50.333-47.301-48.364-47.301-48.364-26.94 0-46.986 21.661-46.986 48.364v106.417h-0.551a31.114 31.114 0 0 1 0.55 5.435 26.466 26.466 0 0 1-26.544 26.86 27.018 27.018 0 0 1-26.546-32.295h-0.55v-156.12c0-45.332-48.76-48.404-48.76-48.404-26.938 0-46.08 21.7-46.08 48.404v123.943h-0.63a26.978 26.978 0 0 1-26.505 32.295 27.018 27.018 0 0 1-26.545-32.295h-0.552V342.37c0-49.112-47.773-48.443-47.773-48.443-26.94 0-46.474 21.662-46.474 48.443v134.538h-0.512a26.978 26.978 0 0 1-26.624 32.296 27.018 27.018 0 0 1-26.545-32.296h-0.512v-328.35c0-26.702-18.432-48.442-45.371-48.442-27.018 0-48.837 21.74-48.837 48.443v516.214c-49.231-48.837-98.383-97.753-147.535-146.629-19.062-18.905-55.257-18.196-74.949 1.575-19.653 19.693-25.758 50.452-1.694 74.595l272.306 270.533c50.53 50.176 117.248 74.91 228.234 74.91 262.262 0 263.05-132.53 263.05-296.055z" p-id="1616" fill="#1890ff"></path></svg>`

// 检测并渲染带身份证号码的文本
const renderTextWithIdCard = (text: string): string => {
  if (!text) return ''
  
  // 转义HTML特殊字符
  const escapeHtml = (str: string) => {
    const div = document.createElement('div')
    div.textContent = str
    return div.innerHTML
  }
  
  // 查找所有身份证号码
  const matches: Array<{ idCard: string; index: number }> = []
  let match
  // 重置正则表达式
  idCardRegex.lastIndex = 0
  while ((match = idCardRegex.exec(text)) !== null) {
    matches.push({
      idCard: match[0],
      index: match.index
    })
  }
  
  if (matches.length === 0) {
    return escapeHtml(text)
  }
  
  // 从后往前替换，避免索引变化
  let result = text
  for (let i = matches.length - 1; i >= 0; i--) {
    const { idCard, index } = matches[i]
    const before = escapeHtml(result.substring(0, index))
    const after = escapeHtml(result.substring(index + idCard.length))
    const idCardHtml = `<span class="id-card-number" data-id-card="${idCard}" draggable="true">${handIconSvg}${escapeHtml(idCard)}</span>`
    result = before + idCardHtml + after
  }
  
  return result
}

// 处理身份证号码拖拽开始
const handleIdCardDragStart = (event: DragEvent) => {
  event.stopPropagation() // 阻止事件冒泡，避免触发节点拖拽
  const target = event.target as HTMLElement
  // 查找最近的.id-card-number元素
  const idCardElement = target.closest('.id-card-number') as HTMLElement
  const idCard = idCardElement?.getAttribute('data-id-card')
  if (idCard && event.dataTransfer) {
    event.dataTransfer.effectAllowed = 'copy'
    event.dataTransfer.setData('text/plain', idCard)
    event.dataTransfer.setData('application/id-card', idCard)
    event.dataTransfer.setData('source-node-id', props.nodeId)
    // 注意：不在这里创建节点，只在 drop 事件中创建，避免重复创建
  }
}

// 处理身份证号码双击创建节点
const handleIdCardDoubleClick = (event: MouseEvent) => {
  event.stopPropagation() // 阻止事件冒泡，避免触发编辑
  event.preventDefault()
  const target = event.target as HTMLElement
  const idCardElement = target.closest('.id-card-number') as HTMLElement
  if (idCardElement) {
    const idCard = idCardElement.getAttribute('data-id-card')
    if (idCard) {
      console.log('双击身份证号码，创建节点:', idCard)
      // 触发创建节点事件
      emit('createPersonNode', idCard)
    }
  }
}

// 处理身份证号码鼠标按下（仅用于阻止事件冒泡，不创建节点）
const handleIdCardMouseDown = (event: MouseEvent) => {
  event.stopPropagation() // 阻止事件冒泡
  // 不在这里创建节点，只在 drop 事件中创建，避免重复创建
}

// 设置身份证号码拖拽事件监听
const setupIdCardDragListeners = () => {
  nextTick(() => {
    if (textBodyRef.value) {
      // 移除旧的事件监听器
      const oldElements = textBodyRef.value.querySelectorAll('.id-card-number')
      oldElements.forEach((el) => {
        el.removeEventListener('dragstart', handleIdCardDragStart)
        el.removeEventListener('mousedown', handleIdCardMouseDown)
        el.removeEventListener('dblclick', handleIdCardDoubleClick)
      })
      
      // 添加新的事件监听器
      const idCardElements = textBodyRef.value.querySelectorAll('.id-card-number')
      idCardElements.forEach((el) => {
        el.addEventListener('dragstart', handleIdCardDragStart)
        el.addEventListener('mousedown', handleIdCardMouseDown)
        el.addEventListener('dblclick', handleIdCardDoubleClick)
      })
    }
  })
}

// 监听文本变化，重新设置事件监听
watch(() => props.text, () => {
  if (!isEditingText.value) {
    setupIdCardDragListeners()
  }
})

onMounted(() => {
  setupIdCardDragListeners()
})

// 监听编辑状态变化
watch(() => isEditingText.value, (newVal) => {
  if (!newVal) {
    // 编辑结束后重新设置事件监听
    setupIdCardDragListeners()
  }
})

const nodeClass = computed(() => ({
  'node-text': true,
  'node-selected': props.selected
}))

const nodeStyle = computed(() => {
  const style: Record<string, string> = {}
  if (props.width !== undefined) {
    style.width = `${props.width}px`
  }
  if (props.height !== undefined) {
    style.height = `${props.height}px`
  }
  return style
})

const handleDelete = () => {
  if (props.nodeId) {
    emit('delete', props.nodeId)
  }
}

// 调整大小相关
const isResizing = ref(false)
const startX = ref(0)
const startY = ref(0)
const startWidth = ref(0)
const startHeight = ref(0)

const handleResizeStart = (e: MouseEvent) => {
  e.preventDefault()
  e.stopPropagation()
  isResizing.value = true
  startX.value = e.clientX
  startY.value = e.clientY
  startWidth.value = props.width || 300
  startHeight.value = props.height || 150
  
  document.addEventListener('mousemove', handleResizeMove)
  document.addEventListener('mouseup', handleResizeEnd)
  document.body.style.userSelect = 'none'
  document.body.style.cursor = 'nwse-resize'
}

const handleResizeMove = (e: MouseEvent) => {
  if (!isResizing.value) return
  const deltaX = e.clientX - startX.value
  const deltaY = e.clientY - startY.value
  const newWidth = Math.max(200, startWidth.value + deltaX)
  const newHeight = Math.max(100, startHeight.value + deltaY)
  emit('resize', props.nodeId, newWidth, newHeight)
}

const handleResizeEnd = () => {
  isResizing.value = false
  document.removeEventListener('mousemove', handleResizeMove)
  document.removeEventListener('mouseup', handleResizeEnd)
  document.body.style.userSelect = ''
  document.body.style.cursor = ''
}

onUnmounted(() => {
  document.removeEventListener('mousemove', handleResizeMove)
  document.removeEventListener('mouseup', handleResizeEnd)
})

// 处理节点鼠标按下事件 - 确保拖拽功能正常
const handleNodeMouseDown = (e: MouseEvent) => {
  // 如果点击的是按钮、调整大小拖拽点或Handle，不阻止事件
  const target = e.target as HTMLElement
  if (
    target.closest('.delete-btn') ||
    target.closest('.resize-handle') ||
    target.closest('.vue-flow__handle') ||
    target.closest('.text-title-input') ||
    target.closest('.text-body-input') ||
    target.closest('.id-card-number')
  ) {
    return
  }
  // 其他区域允许拖拽，不阻止默认行为
}

// 处理节点双击事件
const handleNodeDoubleClick = (e: MouseEvent) => {
  // 如果点击的是按钮、调整大小拖拽点或Handle，不处理双击
  const target = e.target as HTMLElement
  if (
    target.closest('.delete-btn') ||
    target.closest('.resize-handle') ||
    target.closest('.vue-flow__handle') ||
    target.closest('.id-card-number')
  ) {
    return
  }
  console.log('Node double clicked in component:', props.nodeId)
}
</script>

<style scoped lang="less">
.text-node {
  padding: 10px 8px;
  border-radius: 8px;
  min-width: 200px;
  width: 300px;
  min-height: 100px;
  height: auto;
  background: #ffffff;
  border: 2px solid #1890ff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: box-shadow 0.3s ease, border-color 0.3s ease;
  cursor: grab; // 与其他组件保持一致
  position: relative;
  
  &:active {
    cursor: grabbing; // 拖拽时显示grabbing
  }
  overflow: visible; // 改为 visible，确保 Handle 和调整大小点不被裁剪
  box-sizing: border-box;
  display: flex;
  flex-direction: column;

  &:hover {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  }

  // 选中状态样式
  &.node-selected {
    border-color: #1890ff;
    border-width: 3px;
    box-shadow: 0 0 0 3px rgba(24, 144, 255, 0.2), 0 4px 16px rgba(24, 144, 255, 0.3);
  }

  :deep(.vue-flow__handle) {
    width: 4px !important;
    height: 4px !important;
    background: #1890ff !important;
    border: 2px solid #ffffff !important;
    border-radius: 50% !important;
    z-index: 1000 !important;
    opacity: 0.9;
    cursor: crosshair !important;
    pointer-events: auto !important;
    padding: 4px !important;
    margin: -4px !important;
    box-sizing: content-box !important;
    position: absolute !important;

    &:hover {
      opacity: 1 !important;
      background: #40a9ff !important;
      box-shadow: 0 0 8px rgba(24, 144, 255, 0.6) !important;
      z-index: 1001 !important;
    }
  }

  .delete-btn {
    position: absolute;
    top: 4px;
    right: 4px;
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.9);
    border-radius: 4px;
    cursor: pointer;
    z-index: 1002;
    opacity: 1; // 一直显示，与其他组件保持一致
    transition: background-color 0.2s ease;
    color: #8c8c8c;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);

    &:hover {
      background: #ff4d4f;
      color: #ffffff;
    }
  }

  .resize-handle {
    position: absolute;
    bottom: 0;
    right: 0;
    width: 12px;
    height: 12px;
    background: #1890ff;
    border: 2px solid #ffffff;
    border-radius: 50%;
    cursor: nwse-resize;
    z-index: 1002;
    opacity: 0;
    transition: opacity 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
    transform: translate(50%, 50%);

    &:hover {
      opacity: 1 !important;
      background: #40a9ff;
      box-shadow: 0 0 8px rgba(24, 144, 255, 0.6);
    }

    &:active {
      background: #0050b3;
    }
  }

  &:hover .resize-handle {
    opacity: 0.8;
  }

  .progress-container {
    width: 100%;
    height: 100%;
    padding: 20px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-width: 200px;
    min-height: 100px;
    box-sizing: border-box;
  }

  .progress-bar-wrapper {
    width: 100%;
    height: 8px;
    background: #f0f0f0;
    border-radius: 4px;
    overflow: hidden;
    margin-bottom: 12px;
  }

  .progress-bar {
    height: 100%;
    background: linear-gradient(90deg, #1890ff 0%, #40a9ff 100%);
    border-radius: 4px;
    transition: width 0.1s linear;
  }

  .progress-text {
    font-size: 14px;
    font-weight: 600;
    color: #1890ff;
  }

  .text-content {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
    gap: 8px;
  }

  .text-title {
    font-size: 14px;
    font-weight: 600;
    color: #1890ff;
    flex-shrink: 0;
    padding-bottom: 8px;
    border-bottom: 1px solid #e8e8e8;
    cursor: text;
    user-select: none;
    
    &:hover {
      background-color: #f5f5f5;
      border-radius: 4px;
    }
  }

  .text-title-input {
    font-size: 14px;
    font-weight: 600;
    color: #1890ff;
    flex-shrink: 0;
    padding: 4px 8px;
    margin-bottom: 8px;
    border: 2px solid #1890ff;
    border-radius: 4px;
    background: #ffffff;
    width: 100%;
    box-sizing: border-box;
    outline: none;
    cursor: text;
    
    &:focus {
      border-color: #40a9ff;
      box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
    }
  }

  .text-body {
    font-size: 14px;
    line-height: 1.6;
    color: #262626;
    flex: 1;
    overflow-y: auto;
    word-wrap: break-word;
    word-break: break-all;
    min-height: 0;
    cursor: text;
    padding: 4px;
    border-radius: 4px;
    user-select: none;
    
    &:hover {
      background-color: #f5f5f5;
    }
  }

  .text-body-input {
    font-size: 14px;
    line-height: 1.6;
    color: #262626;
    flex: 1;
    padding: 8px;
    border: 2px solid #1890ff;
    border-radius: 4px;
    background: #ffffff;
    width: 100%;
    min-height: 60px;
    resize: vertical;
    box-sizing: border-box;
    outline: none;
    font-family: inherit;
    cursor: text;
    
    &:focus {
      border-color: #40a9ff;
      box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
    }
  }

  // 身份证号码样式
  :deep(.id-card-number) {
    color: #1890ff;
    cursor: grab;
    user-select: none;
    font-weight: 500;
    padding: 2px 4px;
    border-radius: 3px;
    transition: background-color 0.2s ease;

    &:hover {
      background-color: rgba(24, 144, 255, 0.1);
    }

    &:active {
      cursor: grabbing;
    }
  }
}
</style>

